/*
 * Copyright 2006-2008 Michele Mostarda ( michele.mostarda@gmail.com ).
 * All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.graphnav.swing;

import org.graphnav.model.FilteredGraphModel;
import org.graphnav.model.GraphModel;
import org.graphnav.model.ModifiableGraphModel;
import org.graphnav.swing.event.GraphPanelAdapterListener;
import org.graphnav.swing.event.GraphPanelEvent;
import org.graphnav.swing.event.GraphPanelHistoryListener;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;

/**
 * Frame containing the {@link org.graphnav.swing.GraphPanel}  and the {@link org.graphnav.swing.FilterPanel}
 */
public class GraphFrame extends JFrame {

    protected class GraphicsEnancementAction extends AbstractAction {

        GraphicsEnancementAction() {
            super("Grap. Enhancement");
        }

        public void actionPerformed(ActionEvent e) {
            JToggleButton toggleButton = (JToggleButton) e.getSource();
            graphPanel.setGraphicsEnhanced( toggleButton.isSelected() );
        }
    }

    protected class PreviousAction extends AbstractAction {

        PreviousAction() {
            super("Previous");
            //evaluate();
        }

        public void actionPerformed(ActionEvent e) {
            graphPanel.prevHistoryElement();
            evaluateActions();
        }

        void evaluate() {
            setEnabled( graphPanel.hasPreviousHistoryElement() );
        }
    }

    protected class NextAction extends AbstractAction {

        NextAction() {
            super("Next");
            //evaluate();
        }

        public void actionPerformed(ActionEvent e) {
            graphPanel.nextHistoryElement();
            evaluateActions();
        }

        void evaluate() {
            setEnabled( graphPanel.hasNextHistoryElement() );
        }
    }

    protected class NavigateAction extends AbstractAction {
        NavigateAction() {
            super("Navigate");
        }

        public void actionPerformed(ActionEvent e) {
            graphPanel.setMode(GraphPanel.NAVIGATE);
            evaluateActions();
        }

        void evaluate() {
            navigateButton.setSelected(graphPanel.getMode() == GraphPanel.NAVIGATE);
        }
    }

    protected class ViewAllAction extends AbstractAction {
        ViewAllAction() {
            super("View All");
        }

        public void actionPerformed(ActionEvent e) {
            graphPanel.setMode(GraphPanel.VIEW_ALL);
            evaluateActions();
        }

        void evaluate() {
            viewAllButton.setSelected(graphPanel.getMode() == GraphPanel.VIEW_ALL);
        }
    }

    protected static final GridNodeArranger gna = new GridNodeArranger();
    protected static final GridNodeArranger.Options gnao = new GridNodeArranger.Options(10);


    protected class GridArrangeAction extends AbstractAction {

        GridArrangeAction() {
            super("Grid Arrange");
        }

        public void actionPerformed(ActionEvent e) {
            graphPanel.arrange(gna, gnao);

        }
    }

    protected class CreateNodeAction extends AbstractAction {
        CreateNodeAction() {
            super("New Node");
        }

        public void actionPerformed(ActionEvent e) {
            String desc = JOptionPane.showInputDialog("Node Description");
            if(desc == null) { return; }
            Node created = ( (ModifiableGraphModel) graphPanel.getModel()).createNode(desc, new Point(20, 20));
            ( (ModifiableGraphModel) graphPanel.getModel()).addNode(created);

        }
    }

    protected class DetailLevelMediumAction extends AbstractAction {
        DetailLevelMediumAction() {
            super("Detail Med");
        }

        public void actionPerformed(ActionEvent e) {
            graphPanel.setDetailLevel(Renderable.DETAIL_LEVEL_MEDIUM);
            evaluateActions();
        }

        void evaluate() {
            detailLevelMedTButton.setSelected(graphPanel.getDetailLevel() == Renderable.DETAIL_LEVEL_MEDIUM);
        }
    }

    protected class DetailLevelMinimumAction extends AbstractAction {
        DetailLevelMinimumAction() {
            super("Detail Min");
        }

        public void actionPerformed(ActionEvent e) {
            graphPanel.setDetailLevel(Renderable.DETAIL_LEVEL_MINIMAL);
            evaluateActions();
        }

        void evaluate() {
            detailLevelMinTButton.setSelected(graphPanel.getDetailLevel() == Renderable.DETAIL_LEVEL_MINIMAL);
        }
    }

    private static final Dimension GRAPH_PANEL_SCROLL_PANE_DIM = new Dimension(400, 300);

    private static final Dimension CLIPBOARD_PANEL_SCROLL_PANE_DIM = new Dimension(100, 100);

    private JSplitPane horizontalSplit;

    private JSplitPane verticalSplit;

    private GraphPanel graphPanel;

    private JScrollPane graphPanelScrollPane;

    private ClipboardPanel clipboardPanel;

    private JScrollPane clipboardPanelScrollPane;

    private FilterPanel filterPanel;

    private PreviousAction previousAction;

    private NextAction nextAction;

    private NavigateAction navigateAction;

    private ViewAllAction viewAllAction;

    private GridArrangeAction gridArrangeAction;

    private CreateNodeAction createNodeAction;

    private DetailLevelMinimumAction detailLevelMinAction;

    private DetailLevelMediumAction detailLevelMedAction;

    private GraphicsEnancementAction graphicsEnancementAction;

    private JToggleButton detailLevelMinTButton;

    private JToggleButton detailLevelMedTButton;

    private JToggleButton graphicsEnhancementTButton;

    private JToolBar historyToolbar;

    private JToolBar modeToolbar;

    private JToolBar operationsToolbar;

    private JToolBar detailsLevelToolbar;

    private JToggleButton viewAllButton;

    private JButton gridArrangeButton;

    private JToggleButton navigateButton;

    public GraphFrame(GraphModel gm) {
        super("Graph Visualizer");

        filterPanel = new FilterPanel();
        FilteredGraphModel fgm = filterPanel.createFilteredGraphModel(gm);

        graphPanel = new GraphPanel(fgm);
        graphPanel.setDetailLevel(Renderable.DETAIL_LEVEL_MINIMAL);
        graphPanelScrollPane = new JScrollPane(graphPanel);

        graphPanel.addHistoryListener(
            new GraphPanelHistoryListener() {
                public void elementAdded() {
                    previousAction.evaluate();
                    nextAction.evaluate();
                }
            }
        );

        // Allow to resize the graph paenl scroll pane when rearraing of nodes are done. 
        graphPanel.addGraphPanelListener(
                new GraphPanelAdapterListener() {
                    public void panelResized(GraphPanelEvent gpe) {
                        graphPanelScrollPane.revalidate();
                    }
                }
        );

        clipboardPanel = new ClipboardPanel();
        clipboardPanelScrollPane = new JScrollPane(clipboardPanel);

        horizontalSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        verticalSplit   = new JSplitPane(JSplitPane.VERTICAL_SPLIT);

        horizontalSplit.setDividerSize(3);
        verticalSplit.setDividerSize(3);
        horizontalSplit.setResizeWeight(0.10d);
        verticalSplit.setResizeWeight(1.0d);

        clipboardPanelScrollPane.setPreferredSize(CLIPBOARD_PANEL_SCROLL_PANE_DIM);
        horizontalSplit.setLeftComponent( clipboardPanelScrollPane );
        graphPanelScrollPane.setPreferredSize(GRAPH_PANEL_SCROLL_PANE_DIM);
        horizontalSplit.setRightComponent(graphPanelScrollPane );

        verticalSplit.setTopComponent(horizontalSplit);
        verticalSplit.setBottomComponent(filterPanel);


        setLayout(new BorderLayout());

        historyToolbar = new JToolBar();
        modeToolbar = new JToolBar();
        operationsToolbar = new JToolBar();
        detailsLevelToolbar = new JToolBar();

        previousAction = new PreviousAction();
        nextAction     = new NextAction();
        historyToolbar.add(new JButton(previousAction));
        historyToolbar.add(new JButton(nextAction));

        navigateAction = new NavigateAction();
        viewAllAction  = new ViewAllAction();
        gridArrangeAction = new GridArrangeAction();
        navigateButton = new JToggleButton(navigateAction);
        viewAllButton  = new JToggleButton(viewAllAction);
        gridArrangeButton = new JButton(gridArrangeAction);
        modeToolbar.add(viewAllButton);
        modeToolbar.add(navigateButton);
        modeToolbar.add(gridArrangeButton);

        createNodeAction = new CreateNodeAction();
        operationsToolbar.add(createNodeAction);

        detailLevelMedAction = new DetailLevelMediumAction();
        detailLevelMinAction = new DetailLevelMinimumAction();
        graphicsEnancementAction = new GraphicsEnancementAction();
        
        detailLevelMedTButton = new JToggleButton(detailLevelMedAction);
        detailLevelMinTButton = new JToggleButton(detailLevelMinAction);
        graphicsEnhancementTButton = new JToggleButton(graphicsEnancementAction);
        detailsLevelToolbar.add(detailLevelMinTButton);
        detailsLevelToolbar.add(detailLevelMedTButton);
        detailsLevelToolbar.add(graphicsEnhancementTButton);

        JPanel northPanel = new JPanel();
        northPanel.add(historyToolbar);
        northPanel.add(modeToolbar);
        northPanel.add(operationsToolbar);
        northPanel.add(detailsLevelToolbar);

        add(northPanel, BorderLayout.NORTH);
        add(verticalSplit, BorderLayout.CENTER);

        clipboardPanel.addShape(new DefaultNode("test clip 1,", new Point(10, 20)));
        clipboardPanel.addShape(new DefaultNode("test clip 2,", new Point(10, -20)));
        clipboardPanel.addShape(new DefaultNode("test clip 3,", new Point(-110, 20)));

        evaluateActions();
    }

    public GraphPanel getGraphPanel() {
        return graphPanel;
    }

    private void evaluateActions() {
        previousAction.evaluate();
        nextAction.evaluate();
        viewAllAction.evaluate();
        navigateAction.evaluate();
        detailLevelMedAction.evaluate();
        detailLevelMinAction.evaluate();
    }

}
